package com.ygp.dtp.core.monitor;

import com.google.common.collect.Lists;
import com.ygp.dtp.common.config.properties.DtpProperties;
import com.ygp.dtp.common.constant.DynamicTpConstant;
import com.ygp.dtp.common.dto.ThreadPoolState;
import com.ygp.dtp.common.enums.NotifyTypeEnum;
import com.ygp.dtp.common.event.CollectEvent;
import com.ygp.dtp.common.holder.ApplicationContextHolder;
import com.ygp.dtp.core.DynamicThreadPoolRegistry;
import com.ygp.dtp.core.convert.MetricsConverter;
import com.ygp.dtp.core.handler.CollectorHandler;
import com.ygp.dtp.core.notify.AlarmManager;
import com.ygp.dtp.core.thread.DynamicThreadPoolExecutor;
import com.ygp.dtp.core.thread.NamedThreadFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.List;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @description: 线程池监听器
 * <p>
 * springBoot项目启动时，若想在启动之后直接执行某一段代码，就可以用 ApplicationRunner这个接口，
 * 并实现接口里面的run(ApplicationArguments args)方法，方法中写上自己的想要的代码逻辑。
 * @motto: 代码源于生活，高于生活艺术
 * @author: zhouhengzhe
 * @date: 2022/8/9 14:01
 * @since 1.0
 **/
@Slf4j
@Component
public class DtpMonitor implements ApplicationRunner {


    private static final List<NotifyTypeEnum> ALARM_TYPES = Lists.newArrayList(NotifyTypeEnum.LIVE_NESS, NotifyTypeEnum.CAPACITY);

    private static final ScheduledExecutorService MONITOR_EXECUTOR = new ScheduledThreadPoolExecutor(
            1,
            new NamedThreadFactory(DynamicTpConstant.DTP_MONITOR, true));


    @Resource
    private DtpProperties dtpProperties;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        MONITOR_EXECUTOR.scheduleWithFixedDelay(this::run, 0, dtpProperties.getMonitorInterval(), TimeUnit.SECONDS);
    }

    private void run() {
        List<String> dtpNames = DynamicThreadPoolRegistry.listAllDtpNames();
        if (CollectionUtils.isEmpty(dtpNames)) {
            return;
        }
        dtpNames.forEach(i -> {
            DynamicThreadPoolExecutor dynamicThreadPoolExecutor = DynamicThreadPoolRegistry.getExecutor(i);
            AlarmManager.triggerAlarm(() -> AlarmManager.doAlarm(dynamicThreadPoolExecutor, ALARM_TYPES));

            ThreadPoolState threadPoolState = MetricsConverter.convert(dynamicThreadPoolExecutor);
            doCollect(threadPoolState);
        });
        publishEvent();
    }

    /**
     * 准备采集
     *
     * @param threadPoolState
     */
    private void doCollect(ThreadPoolState threadPoolState) {

        if (dtpProperties.isEnabledCollect()) {
            try {
                CollectorHandler.getInstance().collect(threadPoolState, dtpProperties.getCollectorType());
            } catch (Exception e) {
                log.error("动态线程池监视器，指标收集错误。。。", e);
            }
        }
    }

    /**
     * 发布监听事件，具体看DtpWebCollectListener
     */
    private void publishEvent() {
        CollectEvent event = new CollectEvent(this, dtpProperties);
        ApplicationContextHolder.getInstance().publishEvent(event);
    }
}
